import {
  Body,
  Controller,
  Delete,
  Get,
  HttpCode,
  Param,
  Post,
  Put,
  Query,
  Req,
  Res,
  UseGuards,
  UseInterceptors,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { Response } from 'express';
import {
  OperUser,
  SystemUserDecoratorType,
} from 'src/decorator/operuser.decorator';
import { ReqType } from 'src/decorator/reqtype.decorator';
import { AuthItem, Code, jwtConstants, OperType, Role } from 'src/global-type';
import { TokenGuard } from 'src/guard/token.guard';
import { AuthInterceptor } from 'src/interceptor/auth.interceptor';
import { SystemLogService } from 'src/system-log/system-log.service';
import {
  buildSysRecordData,
  getOperInfo,
  TargetType,
} from 'src/system-log/utils';
import { getCurrAuth } from 'src/utils/auth-constants';
import FileLogger from 'src/utils/file-logger';
import { aesDecode, md5 } from 'src/utils/handle-crypto';
import { handleParams } from 'src/utils/handle-params';
import { ifManager } from 'src/utils/utils';
import {
  CreateSystemUserDto,
  ModifyPasswordDto,
  ModifySelfDto,
  UpdateAuthDto,
  UpdateSystemUserDto,
} from './system-user.dto';
import {
  CreateSystemUserType,
  UpdateSystemUserType,
} from './system-user.interface';
import { SystemUserService } from './system-user.service';

const MODULETYPE = 'systemUser';

@Controller('api/system-user/v1.0.0')
@ApiTags('系统用户')
export class SystemUserController {
  private readonly logger = new FileLogger(SystemUserController.name);
  constructor(
    private readonly systemUserService: SystemUserService,
    private readonly jwtService: JwtService,
    private readonly systemLogService: SystemLogService,
  ) { }

  @UseGuards(TokenGuard)
  @Get('/list')
  @ReqType(MODULETYPE, AuthItem.READ)
  @UseInterceptors(AuthInterceptor)
  @ApiOperation({ summary: '获取用户列表' })
  async querySystemUserList(
    @Query() params,
    @OperUser() operUser: SystemUserDecoratorType,
  ) {
    try {
      const { data, sort } = handleParams(params, '+role');
      if (operUser?.role === Role.STAFF) data.role = Role.STAFF;
      const res = await this.systemUserService.querySystemUserList(data, sort);
      this.systemLogService.insertSysLog(operUser, OperType.QUERY, {
        targetType: TargetType.systemUser,
        target: '列表',
        oldData: '',
        newData: '',
      });
      return {
        code: Code.OK,
        message: 'success',
        data: res,
      };
    } catch (err) {
      this.logger.printError(this.querySystemUserList.name, err);
      return {
        code: Code.UNKNOW_ERROR,
        message: String(err),
        data: {
          total: 0,
          data: [],
        },
      };
    }
  }

  @UseGuards(TokenGuard)
  @ReqType(MODULETYPE, AuthItem.CREATE)
  @UseInterceptors(AuthInterceptor)
  @Post('/systemUser')
  @ApiOperation({ summary: '创建系统用户' })
  async createSystemUser(
    @Body() userData: CreateSystemUserDto,
    @OperUser() operUser: SystemUserDecoratorType,
  ) {
    try {
      const { account, userName, password, role, phoneNumber, email } =
        userData;

      const isAccountDup = await this.systemUserService.findOneSystemUser({
        account,
      });
      if (isAccountDup)
        return {
          code: Code.ALREADY_EXIST,
          message: '当前用户账号已存在',
          data: null,
        };

      if (operUser?.role === Role.ENTERPRISE && userName === operUser?.userName)
        return {
          code: Code.ALREADY_EXIST,
          message: '当前用户名不可用',
          data: null,
        };
      if (!password || password.length < 6)
        return {
          code: Code.FORMAT_ERROR,
          message: '密码最小长度为6位',
          data: null,
        };
      const newUser: CreateSystemUserType = {
        userName,
        account,
        password: md5(password),
        role,
        phoneNumber: phoneNumber || '',
        email: email || '',
        ownerName: '',
        auth: '',
      };
      if (role === Role.ENTERPRISE) {
        const isUserNameConflict =
          await this.systemUserService.findOneSystemUser({ userName });
        if (isUserNameConflict)
          return {
            code: Code.ALREADY_EXIST,
            message: '当前用户名不可用',
            data: null,
          };
        newUser.ownerId = account;
        newUser.ownerName = userName;
      } else {
        if (operUser?.role !== Role.ADMIN) {
          newUser.ownerId = operUser?.ownerId;
        }
      }
      const currAuth = await this.systemUserService.createOneAuth(
        getCurrAuth(role, account),
      );
      newUser.auth = currAuth._id;
      const res = await this.systemUserService.createOneSystemUser(newUser);
      await this.systemUserService.updateOneAuth(
        { _id: res.auth },
        { userId: res._id },
      );
      if (!res)
        return {
          code: Code.UNKNOW_ERROR,
          message: '创建失败',
          data: null,
        };
      this.systemLogService.insertSysLog(operUser, OperType.CREATE, {
        target: res.account,
        targetType: TargetType.systemUser,
        oldData: '',
        newData: JSON.stringify(res),
      });
      return {
        code: Code.OK,
        message: 'success',
        data: null,
      };
    } catch (err) {
      this.logger.printError(this.createSystemUser.name, err);
      return {
        code: Code.UNKNOW_ERROR,
        message: String(err),
        data: null,
      };
    }
  }

  @UseGuards(TokenGuard)
  @ReqType(MODULETYPE, AuthItem.MODIFY)
  @UseInterceptors(AuthInterceptor)
  @Put('/systemUser/:id')
  @ApiOperation({ summary: '更新用户信息' })
  async updateSystemUser(
    @Param('id') id: string,
    @Body() userData: UpdateSystemUserDto,
    @OperUser() operUser: SystemUserDecoratorType,
  ) {
    try {
      const targetUser = await this.systemUserService.findOneSystemUser({
        _id: id,
      });
      if (!targetUser)
        return {
          code: Code.NOT_EXiST,
          message: '目标用户不存在，请刷新后重试',
          data: null,
        };
      // TODO: 如果要新增角色,此处应该进一步处理,当前为字符串比较
      if (
        targetUser.role === Role.ADMIN ||
        (operUser?.role !== Role.ADMIN &&
          ((ifManager.get(targetUser.role) && !ifManager.get(operUser.role)) ||
            targetUser.ownerId !== operUser?.ownerId))
      )
        return {
          code: Code.UNAUTHORIZED,
          message: '不具备操作当前用户的操作权限，请联系系统管理员',
          data: null,
        };
      const data4update: UpdateSystemUserType = {
        phoneNumber: userData.phoneNumber || '',
        email: userData.email || '',
      };
      if (userData.userName !== targetUser.userName) {
        if (targetUser.role !== Role.STAFF) {
          const isUserNameConflictInner =
            await this.systemUserService.findOneSystemUser({
              userName: userData.userName,
            });
          const isUserNameConflictAll =
            await this.systemUserService.findOneSystemUser({
              userName: userData.userName,
              role: {
                $in: [Role.ADMIN, Role.ENTERPRISE],
              },
            });
          if (isUserNameConflictInner || isUserNameConflictAll)
            return {
              code: Code.ALREADY_EXIST,
              message: '当前用户名不可用',
              data: null,
            };
        } else {
          const ownerIdUser = await this.systemUserService.findOneSystemUser({
            account: targetUser.ownerId,
          });
          if (userData.userName === ownerIdUser.userName)
            return {
              code: Code.ALREADY_EXIST,
              message: '当前用户名不可用',
              data: null,
            };
        }
        data4update.userName = userData.userName;
      }
      if (userData.password) {
        if (userData.password.length < 6)
          return {
            code: Code.FORMAT_ERROR,
            message: '密码最小长度为6位',
            data: null,
          };
        data4update.password = md5(userData.password);
      }
      if (
        userData.role !== undefined &&
        targetUser.role !== userData.role &&
        operUser.role <= Role.ENTERPRISE
      )
        data4update.role = userData.role;
      const res = await this.systemUserService.udpateOneSystemUser(
        { _id: id },
        { $set: data4update },
      );
      if (!res)
        return {
          code: Code.UNKNOW_ERROR,
          message: '更新失败',
          data: null,
        };
      if (targetUser.role === Role.ENTERPRISE && userData.userName) {
        await this.systemUserService.updateMulSystemUser(
          {},
          { $set: { ownerName: res.ownerName } },
        );
      }
      this.systemLogService.insertSysLog(operUser, OperType.MODIFY, {
        target: targetUser.account,
        targetType: TargetType.systemUser,
        oldData: JSON.stringify(targetUser),
        newData: JSON.stringify(res),
      });
      return {
        code: Code.OK,
        message: 'success',
        data: null,
      };
    } catch (err) {
      this.logger.printError(this.updateSystemUser.name, err);
      return {
        code: Code.UNKNOW_ERROR,
        message: String(err),
        data: null,
      };
    }
  }

  @UseGuards(TokenGuard)
  @ReqType(MODULETYPE, AuthItem.DELETE)
  @UseInterceptors(AuthInterceptor)
  @Delete('/systemUser/:id')
  @ApiOperation({ summary: '删除用户信息' })
  async removeSystemUser(
    @Param('id') id: string,
    @OperUser() operUser: SystemUserDecoratorType,
  ) {
    try {
      const targetUser = await this.systemUserService.findOneSystemUser({
        _id: id,
      });

      if (!targetUser)
        return {
          code: Code.NOT_EXiST,
          message: '不存在的用户，请刷新后重试',
          data: null,
        };

      if (
        targetUser.role === Role.ADMIN ||
        (operUser?.role !== Role.ADMIN &&
          (targetUser.role === Role.ENTERPRISE ||
            operUser?.ownerId !== targetUser.ownerId)) ||
        operUser?.id == targetUser._id
      )
        return {
          code: Code.UNAUTHORIZED,
          message: '不具备操作当前用户的操作权限，请联系管理员',
          data: null,
        };

      const delUserSuccess = await this.systemUserService.deleteOneSystemUser({
        _id: id,
      });

      if (!delUserSuccess)
        return {
          code: Code.UNKNOW_ERROR,
          message: '删除失败，请联系管理员进行处理',
          data: null,
        };

      const delAuthSuccess = await this.systemUserService.deleteOneAuth({
        _id: targetUser.auth,
      });

      if (!delAuthSuccess)
        return {
          code: Code.UNKNOW_ERROR,
          message: '删除角色权限失败，请联系系统管理员进行处理',
          data: null,
        };
      this.systemLogService.insertSysLog(operUser, OperType.DELETE, {
        target: targetUser.account,
        targetType: TargetType.systemUser,
        oldData: JSON.stringify(targetUser),
        newData: '',
      });
      return {
        code: Code.OK,
        message: 'success',
        data: null,
      };
    } catch (err) {
      this.logger.printError(this.removeSystemUser.name, err);
      return {
        code: Code.UNKNOW_ERROR,
        message: String(err),
        data: null,
      };
    }
  }

  @UseGuards(TokenGuard)
  @Get('/companies')
  @ApiOperation({ summary: '获取公司数组' })
  async getCompanies(@Query() params: { name?: string }) {
    try {
      const statement = params.name
        ? {
          userName: new RegExp(params.name),
          role: {
            $in: [Role.ADMIN, Role.ENTERPRISE],
          },
        }
        : {
          role: {
            $in: [Role.ADMIN, Role.ENTERPRISE],
          },
        };
      const res = await this.systemUserService.findMulSystemUsers(
        statement,
        {
          account: 1,
          createTime: 1,
          userName: 1,
        },
        10,
      );
      return {
        code: Code.OK,
        message: 'success',
        data: res?.map((item) => ({
          value: item.account,
          label: item.userName,
        })),
      };
    } catch (err) {
      this.logger.printError(this.getCompanies.name, err);
      return { code: Code.UNKNOW_ERROR, message: String(err), data: [] };
    }
  }

  @Get('/auth')
  @ReqType(MODULETYPE, AuthItem.MODIFY)
  @UseInterceptors(AuthInterceptor)
  @ApiOperation({ summary: '获取权限详情' })
  async getAuth(@Query() params) {
    try {
      const { id } = params;
      const res = await this.systemUserService.findOneAuth({ _id: id });
      if (!res) {
        return {
          code: Code.NOT_EXiST,
          message: '无法获取权限，请联系管理员进行处理',
          data: null,
        };
      }
      return {
        code: Code.OK,
        message: 'success',
        data: res.toObject(),
      };
    } catch (err) {
      this.logger.printError(this.getAuth.name, err);
      return {
        code: Code.UNKNOW_ERROR,
        message: String(err),
        data: null,
      };
    }
  }

  // @Put('/auth/:id')
  // @ReqType(MODULETYPE, AuthItem.MODIFY)
  // @UseInterceptors(AuthInterceptor)
  // @ApiOperation({ summary: '更改权限' })
  // async updateAuth(
  //   @Param('id') id: string,
  //   @Body() newAuthData: UpdateAuthDto,
  //   @OperUser() operUser: SystemUserDecoratorType,
  // ) {
  //   try {
  //     if (!ifManager.get(operUser?.role))
  //       return {
  //         code: Code.UNAUTHORIZED,
  //         message: '无法操作权限分配，请联系管理进行操作',
  //         data: null,
  //       };
  //     const curr = await this.systemUserService.findOneAuth({
  //       _id: id,
  //     });
  //     if (!curr)
  //       return {
  //         code: Code.NOT_EXiST,
  //         message: '无法获取权限，请联系管理员进行处理',
  //         data: null,
  //       };
  //     // TODO: 扩展权限
  //     const {
  //       systemUser,
  //       systemLog,
  //     } = newAuthData;
  //     const res = await this.systemUserService.updateOneAuth(
  //       { _id: id },
  //       {
  //         systemUser,
  //         systemLog,
  //       },
  //     );
  //     if (!res)
  //       return { code: Code.UNKNOW_ERROR, message: '修改失败', data: null };
  //     const targetUser = await this.systemUserService.findOneSystemUser({
  //       _id: curr.userId,
  //     });
  //     this.systemLogService.insertSysLog(
  //       operUser,
  //       OperType.MODIFY,
  //       {
  //         target: targetUser.account,
  //         targetType: TargetType.systemUser,
  //         oldData: JSON.stringify(curr),
  //         newData: JSON.stringify(res),
  //       },
  //       '的权限',
  //     );
  //     return { code: Code.OK, message: '修改成功', data: null };
  //   } catch (err) {
  //     this.logger.printError(this.updateAuth.name, err);
  //     return {
  //       code: Code.UNKNOW_ERROR,
  //       message: String(err),
  //       data: null,
  //     };
  //   }
  // }

  @Post('/login')
  @HttpCode(200)
  @ApiOperation({ summary: '用户登录接口' })
  async login(@Body() userData, @Res() res: Response, @Req() req) {
    try {
      if (!userData.data) {
        res.send({
          code: Code.FORMAT_ERROR,
          message: '请输入账号',
          data: null,
        });
        return {
          code: Code.FORMAT_ERROR,
          message: '请输入账号',
          data: null,
        };
      }
      const parsedUserData = aesDecode(userData.data);
      if (!parsedUserData) {
        res.send({
          code: Code.FORMAT_ERROR,
          message: '验证失败',
          data: null,
        });
        return {
          code: Code.FORMAT_ERROR,
          message: '验证失败',
          data: null,
        };
      }
      const userInfo = await this.systemUserService.findOneSystemUser({
        account: parsedUserData.account,
      });
      if (!userInfo) {
        res.send({
          code: Code.NOT_EXiST,
          message: '当前用户不存在，请确认用户账号是否正确',
          data: null,
        });
        return {
          code: Code.NOT_EXiST,
          message: '当前用户不存在，请确认用户账号是否正确',
          data: null,
        };
      }
      if (userInfo.password !== md5(parsedUserData.password)) {
        res.send({
          code: Code.FORMAT_ERROR,
          message: '密码错误，请重新输入',
          data: null,
        });
        return {
          code: Code.FORMAT_ERROR,
          message: '密码错误，请重新输入',
          data: null,
        };
      }
      const updateUser = await this.systemUserService.udpateOneSystemUser(
        {
          _id: userInfo._id,
        },
        {
          $set: { lastLogin: new Date() },
          $inc: {
            loginTimes: 1,
          },
        },
      );
      const payload = { id: updateUser._id, sub: updateUser.role };
      const token = this.jwtService.sign(payload);
      const newLog = buildSysRecordData(
        getOperInfo(updateUser, req),
        OperType.LOGIN,
        {
          targetType: TargetType.commonInfoPlatform,
          target: '',
          oldData: '',
          newData: '',
        },
      );
      this.systemLogService.createSysLog(newLog);
      res.cookie('token', token);
      res.send({
        code: Code.OK,
        message: 'success',
        data: updateUser,
      });
      return {
        code: Code.OK,
        message: 'success',
        data: updateUser,
      };
    } catch (err) {
      this.logger.printError(this.login.name, err);
      res.send({
        code: Code.UNKNOW_ERROR,
        message: JSON.stringify(err),
        data: null,
      });
      return {
        code: Code.UNKNOW_ERROR,
        message: JSON.stringify(err),
        data: null,
      };
    }
  }

  @UseGuards(TokenGuard)
  @Post('/logout')
  @ApiOperation({ summary: '退出登录后' })
  async logout(@Res() res: Response) {
    res.cookie('token', '');
    res.send({ success: true, data: null });
  }

  @UseGuards(TokenGuard)
  @Get('/currentUser')
  @ApiOperation({ summary: '查询当前用户' })
  async getCurr(@Req() req) {
    try {
      if (!req.cookies) return null;
      const token = req.cookies.token;
      if (!token) return null;
      const tokenObj = this.jwtService.verify(token, {
        secret: jwtConstants.secret,
      });
      const currUser = await this.systemUserService.findOneSystemUser(
        {
          _id: tokenObj.id,
        },
        { password: 0 },
      );
      const auth = await this.systemUserService.findOneAuth(
        {
          _id: currUser.auth,
        },
        { createTime: 0, updateTime: 0 },
      );
      return {
        ...currUser.toObject(),
        auth,
      };
    } catch (err) {
      this.logger.printError(this.getCurr.name, err);
      return {
        code: Code.UNKNOW_ERROR,
        message: String(err),
        data: null,
      };
    }
  }

  @UseGuards(TokenGuard)
  @Put('/self/:id')
  @ReqType(AuthItem.READ)
  @UseInterceptors(AuthInterceptor)
  @ApiOperation({ summary: '更改自己的信息' })
  async modifySelf(
    @Param('id') id: string,
    @Body() userData: ModifySelfDto,
    @OperUser() operUser: SystemUserDecoratorType,
  ) {
    try {
      if (operUser?._id != id)
        return {
          code: Code.UNAUTHORIZED,
          message: '不可操作他人信息！',
          data: null,
        };
      const data4up: UpdateSystemUserType = {};
      if (userData.userName !== operUser?.userName) {
        if (operUser?.role !== Role.STAFF) {
          const isUserNameConflictInner =
            await this.systemUserService.findOneSystemUser({
              userName: userData.userName,
            });
          const isUserNameConflictAll =
            await this.systemUserService.findOneSystemUser({
              userName: userData.userName,
              role: {
                $in: [Role.ADMIN, Role.ENTERPRISE],
              },
            });
          if (isUserNameConflictInner || isUserNameConflictAll)
            return {
              code: Code.ALREADY_EXIST,
              message: '当前用户名不可用',
              data: null,
            };
        } else if (userData.userName === operUser?.ownerName) {
          return {
            code: Code.ALREADY_EXIST,
            message: '当前用户名不可用',
            data: null,
          };
        }
        data4up.userName = userData.userName;
      }
      if (userData.email) data4up.email = userData.email;
      if (userData.phoneNumber) data4up.phoneNumber = userData.phoneNumber;
      const res = await this.systemUserService.udpateOneSystemUser(
        { _id: id },
        {
          $set: data4up,
        },
      );
      if (!res)
        return {
          code: Code.UNKNOW_ERROR,
          message: '更新失败',
          data: null,
        };
      if (operUser?.role === Role.ENTERPRISE && data4up?.userName) {
        await this.systemUserService.updateMulSystemUser(
          {},
          { $set: { ownerName: res.ownerName } },
        );
      }
      this.systemLogService.insertSysLog(operUser, OperType.MODIFY, {
        target: operUser?.account,
        targetType: TargetType.systemUser,
        oldData: '',
        newData: JSON.stringify(res),
      });
      return {
        code: Code.OK,
        message: 'success',
        data: null,
      };
    } catch (err) {
      this.logger.printError(this.modifySelf.name, err);
      return { code: Code.UNKNOW_ERROR, message: String(err), data: null };
    }
  }

  @UseGuards(TokenGuard)
  @Put('/self-password/:id')
  @ReqType(AuthItem.READ)
  @UseInterceptors(AuthInterceptor)
  @ApiOperation({ summary: '更改自身密码' })
  async modifyPassword(
    @Param('id') id: string,
    @Body() userData: ModifyPasswordDto,
    @OperUser() operUser: SystemUserDecoratorType,
    @Res() resp: Response,
  ) {
    try {
      if (operUser?._id != id)
        return {
          code: Code.UNAUTHORIZED,
          message: '不可操作他人信息！',
          data: null,
        };
      const { oldPass, password } = userData;
      if (!oldPass) {
        resp.send({
          code: Code.FORMAT_ERROR,
          message: '请输入原有密码',
          data: null,
        });
        return;
      }
      if (!password) {
        resp.send({
          code: Code.FORMAT_ERROR,
          message: '请输入新密码',
          data: null,
        });
        return;
      }
      if (oldPass === password) {
        resp.send({
          code: Code.FORMAT_ERROR,
          message: '新旧密码不可相同！',
          data: null,
        });
        return;
      }
      if (md5(oldPass) !== operUser?.password) {
        resp.send({
          code: Code.FORMAT_ERROR,
          message: '原密码错误，请重新输入！',
          data: null,
        });
        return;
      }
      const res = await this.systemUserService.udpateOneSystemUser(
        { _id: id },
        {
          $set: {
            password: md5(password),
          },
        },
      );
      if (!res) {
        resp.send({
          code: Code.UNKNOW_ERROR,
          message: '更改失败',
          data: null,
        });
        return;
      }
      this.systemLogService.insertSysLog(operUser, OperType.MODIFY, {
        target: operUser?.account,
        targetType: TargetType.systemUser,
        oldData: '',
        newData: JSON.stringify(res),
      });
      resp.cookie('token', '');
      resp.send({
        code: Code.OK,
        message: 'success',
        data: null,
      });
      return;
    } catch (err) {
      this.logger.printError(this.modifyPassword.name, err);
      resp.send({ code: Code.UNKNOW_ERROR, message: String(err), data: null });
      return;
    }
  }
}
